Curso 3 Limpieza y recolección de datos (Datawrangling)
Raw data VS. Datos Procesados
El objetivo del curso es el siguiente:
- Raw data \(\rightarrow\) script de procesamiento \(\rightarrow\) tidy data \(\rightarrow\) data analysis \(\rightarrow\) data communication
Tidy data
- Cada variable que se mide debe estar en una columna
- Cada observación diferente debe estar en una sóla fila
- Debe haber una tabla por cada tipo de variable
- Si tenemos múltiples tablas, deben incluir una columna en la tabla que les permita enlazarlos.
Trucos:
- Incluir a fila al inicio con los nombres de las variables
- Hacer los nombres de las variables legibles
- En general, los datos deben ser salvados un archivo por cada tabla.
CodeBook
- Información sobre las variables (unidades incluidas!!) del dataset no contenido en el tidy data
- Información sobre las sumarizaciones que se han llevado a cabo
- Información sobre el estudio experimental que se ha usado
Su formato habitual es word/text file. Debe haber una sección llamada “Diseño del estudio” que debe tener una información detallada de cómo se ha recolectado la información, y por último debe tener una sección llamada “Code Book” que describa cada variable y sus unidades.
Instruction list
idealmente es un script en R o en Python, el input del scrip es el raw data y la salida es el tidy data procesado. No debe tener parámetros.
En algunos casos no será posible hacer un script de con algunos de los pasos, en ese caso se debe proporcionar información del tipo:
Paso 1: Tomar el archivo de RawData y ejecutarlo con el software X
Paso 2: Coger la columna tres del archivo de salida y...
....
Ficheros
Un primer caso habitual en la recogida de datos, será descargar de internet dicho fichero de datos. A continuación se describe el mejor proceso para hacerlo.
Descarga de ficheros
- Establecer working directory
- Relativo:
setwd("./data"),setwd("../")= move up in directory - Absoluto:
setwd("/User/Name/data")
- Relativo:
- Comprobar si existe el fichero y descargarlo
if(!file.exists("./data")) {dir.create("./data")}
- Descarga
download.file(url, destfile= "directory/filname.extension", method = "curl")method = "curl"[mac only for https]
dateDownloaded <- date()= record the download date
- Leer el fichero y cargar los datos
read.table()= necesita especificarfile,header,sep,row.names,nrowsread.csv()= automaticamente establecesep = ","andheader = TRUE
quote = ""= no quotes (extremely helpful, common problem)na.strings= establecer el carácter que representa NAnrows= cuántas filas leerskip= cuántas líneas saltarcol.names= especificar el nombre de las columnascheck.names = TRUE/FALSE= si está a TRUE, los nombres de las variables en el dataframe son chequeadas para asegurar que son nombres de variables sintácticamente válidos y no están duplicados, y si no es así intenta adecuarlo
qownnotes-media-Bj1784
qownnotes-media-jX1784
qownnotes-media-fa1784
qownnotes-media-mC1784
qownnotes-media-fX1784
qownnotes-media-Wu1784
Archivos Excel
- xlsx package:
read.xlsx(path, sheetIndex = 1, ...)colIndex,rowIndex= se usa para leer ciertas filas y columnas
write.xlsx()= escribir el fichero a discoread.xlsx2()= más rápido queread.xlsx()pero instable para leer subconjuntos de filasXLConnectpackage más opciones para escribir/manipular archivos excel
qownnotes-media-sQ1784
qownnotes-media-XC1784
qownnotes-media-Is1784
Leer XML
- XML = extensible markup language
- frequented used to store structured data, widely used in Internet apps
- extracción de XML = base para la mayoría de webscrapping
- componentes
- markup = etiquetas que dan la estructura
- contenido = texto real del documento
- tags =
<section>,</section>,<line-break /> - elements =
<Greeting>test</Greeting> - attributes =
<image src ="a.jpg" alt = "b"> - leer archivo en R
library(XML)doc <- xmlTreeParse(fileUrl, useInternal = TRUE)= loads datarootNode <- xmlRoot(doc)= wrapper element for entire documentxmlName(rootNode)= returns name of the documentnames(rootNode)= return names of elementsrootNode[[1]]= access first elements, similar to listrootNode[[1]][[1]]= first sub component in the first elementxmlSApply(rootNode, xmlValue)= returns every single tagged element in the doc
- XPath (new language)
- get specific elements of document
/node= top level node//node= node at any levelnode[@attr-name = 'bob']= node with attribute namexpathSApply(rootNode, "//name", xmlValue)= get the values of all elements with tag “name”xpathSApply(rootNode, "//price", xmlValue)= get the values of all elements with tag “price”
- extraer contenido por atributos
doc <- htmlTreeParse(url, useInternal = True)scores <- xpathSApply(doc, "//li[@class='score']", xmlvalue)= busca elementos li conclass = "score"y devuelve su valor
qownnotes-media-jb1784
qownnotes-media-Gj1784
qownnotes-media-lK1784
qownnotes-media-cN1784
Otro ejemplo
qownnotes-media-dB1784
Leer JSON
- JSON = JavaScript Object Notation
- almacenamiento ligero de datos, formato común para datos desde una API
- similar a XML en estructura pero diferente sintaxis
- los datos se pueden guardar como:
- numbers (double)
- strings (double quoted)
- boolean (true/false)
- array (ordered, comma separated enclosed in
[]) - object (unordered, comma separated collection of key/value pairs enclosed in
{})
jsonlitepackage (json vignette can be found in help)library(jsonlite)= loads packagedata <- fromJSON(url)= strips datanames(data$owner)= returns list of names of all columns of owner data framedata$owner$login= returns login instances
data <- toJSON(dataframe, pretty = TRUE)= converts data frame into JSON formatpretty = TRUE= formats the code nicely
cat(data)= prints out JSON code from the converted data framefromJSON()= converts from JSON object/code back to data frame
qownnotes-media-Zt1784
qownnotes-media-Eu1784
qownnotes-media-Kl1784
qownnotes-media-wn1784
DATA.TABLE
Es una versión más rápida y eficiente que los data.frames en algunas ocasiones.
- hereda de
data.frame(external package) \(\rightarrow\) todas las funciones que aceptandata.framefuncionan condata.table - puede ser (escrito en C), mucho mucho más rápido agrupando,subsetting y actualizando
- sintaxis:
dt <- data.table(x = rnorm(9), y = rep(c("a","b","c"), each = 3), z = rnorm(9)) tables()= returns all data tables in memory- shows name, nrow, MB, cols, key
- some subset works like before =
dt[2, ], dt[dt$y=="a",]dt[c(2, 3)]= subset by rows, rows 2 and 3 in this case
- Subconjuntos de colulmnas (modified for
data.table)- argument after comma is called an expression (collection of statements enclosed in
{}) dt[, list(mean(x), sum(z))]= returns mean of x column and sum of z column (no""needed to specify column names, x and z in ejemplo)dt[, table(y)]= get table of y value (perform any functions)
- argument after comma is called an expression (collection of statements enclosed in
- añadir nuevas columnas
dt[, w:=z^2]- when this is performed, a new data.table is created and data copied over (not good for large datasets)
dt2 <- dt; dt[, y:= 2]- when changes are made to dt, changes get translated to dt2
- Note: if copy must be made, use the
copy()function instead
- operaciones múltiples
dt[, m:= {temp <- (x+z); log2(temp +5)}]\(\rightarrow\) adds a column that equals log2(x+z + 5)
- plyr like operations
dt[,a:=x>0]= creates a new column a that returns TRUE if x > 0, and FALSE other wisedt[,b:=mean(x+w), by=a]= creates a new column b that calculates the aggregated mean forx + wfor when a = TRUE/FALSE, meaning every b value is gonna be the same for TRUE, and others are for FALSE
- variables especiales
.N= returns integer, length 1, containing the number (essentially count)dt <- data.table (x=sample(letters[1:3], 1E5, TRUE))= generates data tabledt[, .N, by =x]= crea una tabla para contar observaciones agrupadas en x
- keys (filtrar/subconjuntos rápidos)
- ejemplo:
dt <- data.table(x = rep(c("a", "b", "c"), each = 100), y = rnorm(300))= generates data tablesetkey(dt, x)= establece la key en la columna xdt['a']= devuelve un data frame, donde x = ‘a’ (effectively filter)
- ejemplo:
- joins (merging tables)
- ejemplo:
dt1 <- data.table(x = c('a', 'b', ...), y = 1:4)= generates data tabledt2 <- data.table(x= c('a', 'd', ...), z = 5:7)= generates data tablesetkey(dt1, x); setkey(dt2, x)= sets the keys for both data tables to be column xmerge(dt1, dt2)= devuelve una tabla, combina las dos tablas usando la columna x filtrando sólo los valores que coinciden entre las dos columnas x y los junta
- ejemplo:
- lectura rápida de ficheros
- ejemplo:
big_df <- data.frame(rnorm(1e6), rnorm(1e6))= generates data tablefile <- tempfile()= generates empty temp filewrite.table(big_df, file=file, row.names=FALSE, col.names = TRUE, sep = "\t", quote = FALSE)= escribe los datos generados de big_df en tempfilefread(file)= lee el archivo y carga los datos mucho más rápido queread.table()
- ejemplo:
qownnotes-media-mH5784
qownnotes-media-td5784
qownnotes-media-Ns5784
qownnotes-media-xr5784
qownnotes-media-bu5784
qownnotes-media-HL5784
qownnotes-media-Mc5784
qownnotes-media-RF5784
qownnotes-media-dl5784
qownnotes-media-LS5784
qownnotes-media-Iz5784
Una manera de hacer subconjuntos muy rápido es crear claves
qownnotes-media-Ia5784
qownnotes-media-eV5784
qownnotes-media-xN5784
Acceso a base de datos
MYSQL
qownnotes-media-mC5784
qownnotes-media-Nw5784
qownnotes-media-af5784
qownnotes-media-tc5784
qownnotes-media-Wf5784
qownnotes-media-cO5784
RODBC
#RJDBC will run quicker because it converts date to character and everything else to numeric.
#RODBC will try to preserve the data type of the SQL table.
#If RODBC is very slow, would make sure that your R timezone - sys.setenv(TZ='GMT') set to GMT for example
#- is same as the time zone of the SQL server from where you are pulling data.
#It could be that the date column is taking a long time to be interpreted especially if it has a timestamp.
#See performance query
#system.time(df <- sqlQuery(cn, query))
#RODBC
install.packages("RODBC")
library(RODBC)
#DD1 would be the DSN
con <- odbcConnect("DD1", uid="rquser", pwd="rquser", rows_at_time = 500)
sqlSave(con,test_table, "TEST_TABLE")
sqlQuery(con,"select count(*) from TEST_TABLE")
d <- sqlQuery(con, "select * from TEST_TABLE")
close(con)RORACLE
##RORACLE
##Special instructions are needed for installing RORacle, since it needs to be downloaded and compiled.
library(RCurl)
zipi <- getURLContent("http://download.oracle.com/otn/nt/roracle/ROracle_1.3-1.zip")
install.packages(zipi, repos = NULL)
#Download binary from oracle: http://www.oracle.com/technetwork/database/database-technologies/r/roracle/downloads/index.html
setwd('C:\\Users\\MH026898\\Downloads') # set to path of download
install.packages('ROracle_1.3-1.zip', repos = NULL)
#Then load the library and use the package - you may have to change XXXX to whatever is in your TNS Names:
library(ROracle)
drv <- dbDriver("Oracle")
con <- dbConnect(drv, "rquser", "rquser")
dbWriteTable(con,"TEST_TABLE", test_table)
dbGetQuery(con,"select count(*) from TEST_TABLE")
d <- dbReadTable(con, "TEST_TABLE")
dbDisconnect(con)
library('ROracle')
drv <- dbDriver("Oracle")
con <- dbConnect(drv, "USER GOES HERE", "PASSWORD GOES HERE", dbname='XXX')
#test connection:
dbReadTable(con, 'DUAL')
#Use conection string instead of TNS NAMES
library('ROracle')
drv <- dbDriver("Oracle")
host <- "10.181.85.198"
port <- 1521
sid <- "cws"
connect.string <- paste(
"(DESCRIPTION=",
"(ADDRESS=(PROTOCOL=tcp)(HOST=", host, ")(PORT=", port, "))",
"(CONNECT_DATA=(SID=", sid, ")))", sep = "")
## Use username/password authentication.
con <- dbConnect(drv, "reports", "reports", dbname=connect.string)
##test connection:
rs <- dbSendQuery(con, "select * from parametros_birt")
## We now fetch records from the resultSet into a data.frame.
data <- fetch(rs) ## extract all rows
dim(data)
dbDisconnect(con)
RJDBC
#USING RJDBC
ConnectDB = function(){
library(rJava)
library(RJDBC)
.jinit()
drv <- JDBC(driverClass="oracle.jdbc.OracleDriver", classPath="jdbcDrivers/Oracle/ojdbc6.jar")
drv <- JDBC(driverClass="oracle.jdbc.OracleDriver", classPath="./ojdbc6.jar")
con <- dbConnect(drv, "jdbc:oracle:thin:@//IPADRESS:PORT/SERVICENAME", "user", "passw")
return(con)
}
con <- ConnectDB()
#It can be used other drivers for jdbc
library(RJDBC)
drv <- JDBC("com.microsoft.sqlserver.jdbc.SQLServerDriver","/sqljdbc4.jar")
con <- dbConnect(drv, "jdbc:sqlserver://server.location", "username", "password")
dbGetQuery(con, "select column_name from table")
Acceos a HDF5
qownnotes-media-CC5784
qownnotes-media-ZB5784
qownnotes-media-aO5784
qownnotes-media-zd5784
qownnotes-media-bP5784
qownnotes-media-Wn5784
Webscraping ————-
qownnotes-media-zT5784
qownnotes-media-Cf5784
qownnotes-media-pX5784
qownnotes-media-hM5784
qownnotes-media-XE5784
qownnotes-media-UB5784
qownnotes-media-ec5784
qownnotes-media-Oz5784
Otros recursos
qownnotes-media-it5784
qownnotes-media-kU5784
qownnotes-media-Ei5784
qownnotes-media-gL5784
Expresiones regulares
- RegEx = combinación de literales y metacaracteres
- usado junto a las funciones
grep/grepl/sub/gsubo cualquier otra que suponga burcar cadenas ^= comienzo de línea (metacharacter)- ejemplo:
^textdetecta “text …”
- ejemplo:
$= final de línea (metacharacter)- ejemplo:
text$detecta “… text”
- ejemplo:
[]= conjunto de caracteres que serán aceptados en la detección (character class)- ejemplo:
^[Ii]detecta “I …” or “i …”
- ejemplo:
[0-9]= buscar por un rango de caracteres (character class)- ejemplo:
[a-zA-Z]detecta cualquier letra mayúscula o minúscula
- ejemplo:
[^?.]= cuando se usa al inicio de un character class, “^” significa anular el metacaracter (metacharacter)- ejemplo:
[^?.]$detecta cualquier lúna que no acabe en en “.” or “?”
- ejemplo:
.= cualquier carácter (metacharacter)- ejemplo:
9.11detecta 9/11, 9911, 9-11, etc
- ejemplo:
|= or, usado para combinar subexpresiones llamadas alternatives (metacharacter)- ejemplo:
^([Gg}ood | [Bb]ad)detecta cualquier línea que empiece con may/min “Good…” and “Bad …” - Nota:
()limita el alcance de las alternatives separadas por “|” aquí
- ejemplo:
?= expresión opcional = 0/1 de algún carácter o expresión (metacharacter)- ejemplo:
[Gg]eorge( [Ww]\.)?[Bb]ush detecta “george bush”, “George W. Bush” - Nota: “" se añade antes de”." porque “.” es un metacarácter, “.” se llama punto escapado, le dice a la expresion que lea realmete un punto en lugar del operador
- ejemplo:
*= cualquier número de repetición, incluyendo ninguna = 0 o más de algún carácter/expresión (metacharacter)- ejemplo:
.*detecta cualquier combinación de caractéres - Nota:
*es ambicioso = siempre detecta la cadena más larga que satisface la expression regular- greediness of
*puede anularse con? - ejemplo:
s.*?sdetecta el texto más corto “s…s”
- greediness of
- ejemplo:
+= 1 o más repeticiones = 1 o más carácter/expresión (metacharacter)- ejemplo:
[0-9]+detecta al menos 1 dígito de números como “0”, “90”, or “021442132”
- ejemplo:
{m, n}= cuantificador de intervalo, permite especificar el mínimo y máximo número de detecciones (metacharacter)m= mínimo,n= no más de{m}= exactamentemdetecciones{m, }= al menos m detecciones- ejemplo:
Bush( +[^ ]+ +){1, 5}debates detecta “Bush + (al menos 1 espacio + cualquier palabra que no contenga espacio + al menos 1 espacio) repiendo este patrón entre 1 y 5 veces + debates”
()= define un grupo como el siguiente entre paréntesis, los grupos se recuerdan y pueden ser referidos como\1,\2, etc.- ejemplo:
([a-zA-Z]+) +\1 +detecta “cualquier palabra + al menos 1 espacio + la misma palabra repetida + al menos un espacio” = “night night”, “so so”, etc.
- ejemplo:
Trabajar con fechas
date()= devuelve fecha actual en formato carácterSys.Date()= devuelve fecha actual en formato Dateformat(object, "format")= da formato a un objeto con el patrón- cuano el objecto = Date:
%d= day as number (0-31)%a= abbreviated weekday%A= unabbreviated weekday%m= month (00-12%b= abbreviated month%B= unabbreviated month%y= 2 digit year%Y= 4 digit year
- ejemplo:
format(Sys.Date(), "%a %b %d")= devuelve “Sun Jan 18”
- cuano el objecto = Date:
as.Date("character", "format")= convierte el string en Date formateando- ejemplo:
z <- as.Date("1jan1960", "%d%b%Y")= crea la fecha “1960-01-01”
- ejemplo:
Date1 - Date2= diferencia en día imprimiendo “Time difference of n days”as.numeric()devuelve la diferencia en número
weekdays(Date),months(Date)= devuelve el día de la semana/mesjulian(Date)= COnvierte la fecha en el número de días que han pasado desde el origenattr(, "origin")= imprime el origen en formato fecha, que es 1970-01-01
lubridatepackage [library(lubridate)]?Sys.timezone= documentación de cómo determinar timezones
Lubridate
- consistent, memorable syntax for working with dates
wday(date, label = TRUE)= devuelve el número 1 - 7 representando Sunday - Saturday, o devuelve tres letras del día si label = TRUEtoday(),now()= devuelve día y hora actual, con partes extraíbles (hour(), month())tzone = "America/New_York"= usado para especificar time zones (list here)
ymd("string")= convierte un string en year month day format a una variable de tiempo POSIXctmdy("string")= parses date in month day year formatdmy(2508195)= parses date in day month year format using a numberymd_hms("string")= parses the year month day, hour minute secondhms("string")= parses hour minute secondtz = ""= can use the “tz” argument to specify time zones
- Nota: existe uan variedad de funciones disponibles para parsear distintos formatos, todos ellos capaces de convertir la información correcta si el orden de mes dia año es correcto
- Nota: cuando sea necesario,
//o'deber ser añadido para clarificar
update(POSIXct, hours = 8, minutes = 34, seconds = 55)= acutaliza componentes de una hora- Nota: does not alter the date time passed in unless explicitly assigned
- arithmetic can be performed on date times by using the
days()hours()minutes(), etc. functions- ejemplo:
now() + hours(5) + minutes(2)= returns the date time for 5 hours and 2 minutes from now
- ejemplo:
with_tz(time, tone ="")= return date-time in a different time zoneas.period(new_interval(last_time, arrive))= return the properly formatted difference between the two date times
DPLYR VS DATAFRAME
CREAR COLUMNA
Dataframe
data$nuevoNombre <- ifelse(data$name=='TORNADO';'TOR';data$name)
Dplyr
data %>%
mutate(nuevoNombre = ifelse(data$name=='TORNADO';'TOR';data$name))
msleep %>%
mutate(rem_proportion = sleep_rem / sleep_total)
AGRUPAR
Agregate
INJ <- aggregate(INJURIES ~ EVTYPE, data, FUN = sum)
Data table
DT <- data.table(data)
INJ <- DT[,sum(INJURIES),by=EVTYPE]
Dplyr
INJ <- data %>% groupby(EVTYPE)%>%summarise(total.sum=sum(INJURIES)
ORDENAR
DataFrame
INJ <- INJ[order(-INJ$V1),]
Dplyr
INJ <- arrange(INJ, desc(V1))
# grouped arrange ignores group
INJ %>% arrange(desc(V1))
# Unless you specifically ask:
INJ %>% arrange(desc(V1), .bygroup = TRUE)
SELECCIONAR
Dataframe
event <- c("EVTYPE", "FATALITIES", "INJURIES", "PROPDMG", "PROPDMGEXP", "CROPDMG",
"CROPDMGEXP")
data <- storm[event]
dplyr
data <- select(storm, EVTYPE, FATALITIES,INJURIES,PROPDMG)
FILTRAR
Dataframe
data$CROPEXP[data$CROPDMGEXP == "2"]
dplyr
filter(data, CROPDMGEXP >= 16)